package com.hmall.order.service.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.client.UserClient;
import com.hmall.common.client.ClientFeign;
import com.hmall.common.entry.BaseContext;
import com.hmall.common.pojo.Address;
import com.hmall.common.pojo.item.Item;
import com.hmall.common.vo.ItemVO;
import com.hmall.order.constans.StatusConstans;
import com.hmall.order.mapper.OrderDetailMapper;
import com.hmall.order.mapper.OrderLogisticsMapper;
import com.hmall.order.mapper.OrderMapper;
import com.hmall.order.pojo.Order;
import com.hmall.order.pojo.OrderDetail;
import com.hmall.order.pojo.OrderLogistics;
import com.hmall.order.pojo.RequestParams;
import com.hmall.order.service.IOrderService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.UUID;

@Service
public class OrderService extends ServiceImpl<OrderMapper, Order> implements IOrderService {
    @Resource
    private ClientFeign clientFeign;
    @Resource
    private UserClient userClient;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private OrderDetailMapper orderDetailMapper;
    @Resource
    private OrderLogisticsMapper orderLogisticsMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * TODO 方法体太长，缺乏关键步骤提炼
     * 创建订单
     * @param params
     * @return
     */
    @GlobalTransactional
    @Override
    public Long placeOrder(RequestParams params) {
        //1.雪花生成订单id
        long xuehuaId = IdWorker.getId();
        Order order = new Order();
        //2.使用feign根据id查询商品
        Item item = clientFeign.seleceById(params.getItemId());
        //3.基于商品价格、购买数量计算商品总价totalFee
        Double totalFee = Double.valueOf(params.getNum() * item.getPrice());
        //4.封装Order对象,并将Order写入数据库表中
        order111(params, xuehuaId, order, totalFee);
        //5.封装OrderDetail对象,将OrderDetail写入数据库表中
        orderDetail111(params, order, item);
        //6.根据addressId查询user-service服务，获取地址信息,
        // 将地址封装为OrderLogistics对象,将OrderLogistics写入数据表
        getAddressAndOrderLogistics(params, order);
        //7.扣减（更新）库存
        updateStock(params);
        //8.延迟消息发送
        delayedMsg(order.getId());
        //9.返回id
        return order.getId();
    }

    private void order111(RequestParams params, long xuehuaId, Order order, Double totalFee) {
        //4.封装Order对象,并将Order写入数据库表中
        order.setTotalFee(totalFee);
        order.setPaymentType(params.getPaymentType());
        order.setUserId(BaseContext.getCurrentId());
        order.setStatus(StatusConstans.UNPAID);
        order.setId(xuehuaId);
        order.setCreateTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        orderMapper.insert(order);
    }

    private void orderDetail111(RequestParams params, Order order, Item item) {
        //5.封装OrderDetail对象
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderId(order.getId());
        orderDetail.setItemId(item.getId());
        orderDetail.setSpec(item.getSpec());
        orderDetail.setNum(params.getNum());
        orderDetail.setImage(item.getImage());
        orderDetail.setName(item.getName());
        orderDetail.setPrice(item.getPrice());
        orderDetail.setCreateTime(LocalDateTime.now());
        orderDetail.setUpdateTime(LocalDateTime.now());
        //5.1将OrderDetail写入数据库表中
        orderDetailMapper.insert(orderDetail);
    }

    private void getAddressAndOrderLogistics(RequestParams params, Order order) {
        //6.根据addressId查询user-service服务，获取地址信息
        Address address = userClient.getAddressId(params.getAddressId());
        //6.1将地址封装为OrderLogistics对象
        OrderLogistics orderLogistics = new OrderLogistics();
        BeanUtils.copyProperties(address,orderLogistics);
        orderLogistics.setOrderId(order.getId());
        orderLogistics.setCreateTime(LocalDateTime.now());
        orderLogistics.setUpdateTime(LocalDateTime.now());
        //6.2将OrderLogistics写入数据表
        orderLogisticsMapper.insert(orderLogistics);
    }

    /**
     * 7.扣减库存
     * @param params
     * @param
     */
    public void updateStock(RequestParams params) {
        ItemVO result = new ItemVO();
        Item item = clientFeign.seleceById(params.getItemId());
        //1.查询现有库存
        if (Objects.isNull(item)){
            result.setUpdateResult(Boolean.FALSE);
            result.setUpdateMsg("库存数据不存在，请稍后重试");
            return;
        }
        //2.数据合法性校验
        if (item.getStock() < params.getNum()){
            result.setUpdateResult(Boolean.FALSE);
            result.setUpdateMsg("库存不足，请稍后重试");
            return;
        }
        //3.扣减库存
        Integer inventoryCount = item.getStock() - params.getNum();
        clientFeign.updateInventory(params.getItemId(), inventoryCount);

        //4.更新结果判断
        if (inventoryCount < 1){
            result.setUpdateResult(Boolean.FALSE);
            result.setUpdateMsg("库存数据不存在，请稍后重试");
            return;
        }
        result.setUpdateResult(Boolean.TRUE);
        result.setUpdateMsg("更新成功");
        return;
    }

    /**
     *  延迟消息发送
     * @param orderId
     */
    public void delayedMsg(Long orderId) {
        // 创建消息
        Message message = MessageBuilder
                .withBody(String.valueOf(orderId).getBytes(StandardCharsets.UTF_8))
                .setHeader("x-delay",5000)
                .build();
        // 消息ID，需要封装到CorrelationData中
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        // 发送消息
        rabbitTemplate.convertAndSend("order.direct", "order", message, correlationData);
        log.debug("发送消息成功");
    }

}





